<template>
    <view class="u-slider" @tap="onClick" :disabled="disabled" :style="{
        backgroundColor: inactiveColor
    }">
        <view class="u-slider__gap" :style="[
            barStyle,
            {
                height: height + 'rpx',
                backgroundColor: activeColor
            }
        ]">
            <view class="u-slider__button-wrap" @touchstart="onTouchStart" @touchmove="onTouchMove" @touchend="onTouchEnd"
                @touchcancel="onTouchEnd" :style="{ right: isWidth ? '10rpx' : '-7rpx' }">
                <slot v-if="$slots.default || $slots.$default" />
                <view v-else class="u-slider__button"></view>
            </view>
        </view>
    </view>
</template>

<script>
export default {
    name: 'u-slider',
    props: {
        // 当前进度百分比值，范围0-100
        value: {
            type: [Number, String],
            default: 0
        },
        // 是否禁用滑块
        disabled: {
            type: Boolean,
            default: true
        },
        // 滑块宽度，高等于宽，单位rpx
        blockWidth: {
            type: [Number, String],
            default: 30
        },
        // 最小值
        min: {
            type: [Number, String],
            default: 0
        },
        // 最大值
        max: {
            type: [Number, String],
            default: 100
        },
        // 步进值
        step: {
            type: [Number, String],
            default: 1
        },
        // 滑块条高度，单位rpx
        height: {
            type: [Number, String],
            default: 6
        },
        // 进度条的激活部分颜色
        activeColor: {
            type: String,
            default: '#FD8200'
        },
        // 进度条的背景颜色
        inactiveColor: {
            type: String,
            default: '#CC0B17'
        },
        // 滑块的背景颜色
        blockColor: {
            type: String,
            default: '#FD8200'
        },
        // 用户对滑块的自定义颜色
        blockStyle: {
            type: Object,
            default() {
                return {};
            }
        },
    },
    data() {
        return {
            startX: 0,
            status: 'end',
            newValue: 0,
            distanceX: 0,
            startValue: 0,
            barStyle: {},
            sliderRect: {
                left: 0,
                width: 0
            },
            isWidth: 0
        };
    },
    watch: {
        value(n) {
            // 只有在非滑动状态时，才可以通过value更新滑块值，这里监听，是为了让用户触发
            if (this.status == 'end') this.updateValue(this.value, false);
        }
    },
    created() {
        this.updateValue(this.value, false);
    },
    mounted() {
        // 获取滑块条的尺寸信息
        const query = uni.createSelectorQuery().in(this)
        query.select(".u-slider").boundingClientRect(rect => {
            this.sliderRect = rect;
        }).exec()
        // this.$uGetRect('.u-slider').then(rect => {
        // 	this.sliderRect = rect;
        // });
    },
    methods: {
        onTouchStart(event) {
            if (this.disabled) return;
            this.startX = 0;
            // 触摸点集
            let touches = event.touches[0];
            // 触摸点到屏幕左边的距离
            this.startX = touches.clientX;
            // 此处的this.value虽为props值，但是通过$emit('input')进行了修改
            this.startValue = this.format(this.value);
            // 标示当前的状态为开始触摸滑动
            this.status = 'start';
        },
        onTouchMove(event) {
            if (this.disabled) return;
            // 连续触摸的过程会一直触发本方法，但只有手指触发且移动了才被认为是拖动了，才发出事件
            // 触摸后第一次移动已经将status设置为moving状态，故触摸第二次移动不会触发本事件
            if (this.status == 'start') this.$emit('start');
            let touches = event.touches[0];
            // 滑块的左边不一定跟屏幕左边接壤，所以需要减去最外层父元素的左边值
            this.distanceX = touches.clientX - this.sliderRect.left;
            // 获得移动距离对整个滑块的百分比值，此为带有多位小数的值，不能用此更新视图
            // 否则造成通信阻塞，需要每改变一个step值时修改一次视图
            this.newValue = (this.distanceX / this.sliderRect.width) * 100;
            this.status = 'moving';
            // 发出moving事件
            this.$emit('moving');
            this.updateValue(this.newValue, true);
        },
        onTouchEnd() {
            if (this.disabled) return;
            if (this.status === 'moving') {
                this.updateValue(this.newValue, false);
                this.$emit('end');
            }
            this.status = 'end';
        },
        updateValue(value, drag) {
            // 去掉小数部分，同时也是对step步进的处理
            const width = this.format(value);
            // 不允许滑动的值超过max最大值，百分比也不能超过100
            if (width > this.max || width > 100) return;
            // 设置移动的百分比值
            let barStyle = {
                width: width + '%'
            };
            // console.log('width', width)
            this.isWidth = width
            // 移动期间无需过渡动画
            if (drag == true) {
                barStyle.transition = 'none';
            } else {
                // 非移动期间，删掉对过渡为空的声明，让css中的声明起效
                delete barStyle.transition;
            }
            // 修改value值
            this.$emit('input', width);
            this.barStyle = barStyle;
        },
        format(value) {
            // 将小数变成整数，为了减少对视图的更新，造成视图层与逻辑层的阻塞
            return Math.max(this.min, Math.min(value, this.max) / this.step) * this.step;
        },
        onClick(event) {
            if (this.disabled) return;
            // 直接点击滑块的情况，计算方式与onTouchMove方法相同
            const value = ((event.detail.x - this.sliderRect.left) / this.sliderRect.width) * 100;
            this.updateValue(value, false);
        }
    }
};
</script>

<style lang="scss" scoped>
// @import "../../libs/css/style.components.scss";

.u-slider {
    position: relative;
    border-radius: 999rpx;
    border-radius: 999rpx;
    border: 4rpx solid #F9C600;
}

.u-slider:before {
    position: absolute;
    right: 0;
    left: 0;
    content: '';
    top: -8rpx;
    bottom: -8rpx;
    z-index: -1;
}

.u-slider__gap {
    position: relative;
    border-radius: inherit;
    transition: width 0.2s;
    transition: width 0.2s;
}

.u-slider__button {
    width: 100rpx;
    height: 55rpx;
    border-radius: 50%;
    background-image: url("https://new.qingfentool.vip/upload/image/20230713/cfe779bf980d655dd9a69a71cde2c24e.png");
    background-size: 100% 100%;
    cursor: pointer;
}

.u-slider__button-wrap {
    position: absolute;
    top: 50%;
    transform: translate3d(40%, -47%, 0);
}
</style>
